--------------Muppetville--------------
A 4am crack                  2022-06-10
---------------------------------------

Name: Muppetville
Version: rev. 2 (*)
Genre: educational
Year: 1986
Publisher: Sunburst Communications
Platform: Apple ][+ or later (64K)
Media: 5.25-inch disk
Sides: 1
OS: ProDOS 1.1.1
Previous cracks: none (of this version)
Similar cracks:
  #2157 Building Perspective
  #2085 Charlotte's Web
  #2039 Word-a-mation

(*) Compared to 4am crack no. 265, this
    version changes the name of a file
    from "PROMP" to "PROMPTS.IMG" and
    makes other unspecified changes
    in LOADER.SYSTEM.

                   ~

               Chapter 0
 In Which Various Automated Tools Fail
          In Interesting Ways


COPYA
  immediate disk read error

Locksmith Fast Disk Backup
  unable to read any track

EDD 4 bit copy (no sync, no count)
  no read errors, but copy loads ProDOS
  title screen, then reboots

Copy ][+ nibble editor
  T00 has at least a few sectors, but
    I'm not sure how many
  T01+ have no visible structure at all

                 --v--

   COPY ][ PLUS BIT COPY PROGRAM 8.4
(C) 1982-9 CENTRAL POINT SOFTWARE, INC.
---------------------------------------

TRACK: 03  START: 1800  LENGTH: 3DFF

18F8: F4 96 CB FF 9B 9B AA D5   VIEW
1900: FE FF FE FF FF F9 CF D3
1908: F3 99 E6 99 E6 99 E6 99
1910: E6 99 E6 99 E6 99 E6 99
1918: CA AA A9 9B B2 AF 96 AA  <-1918
1920: D5 FC 99 E6 99 E6 99 E6
1928: 99 E6 99 E6 99 E6 CA D5
1930: A9 AE FA F3 9A 96 B7 DE
1938: F3 96 ED 96 ED F5 B9 9A

---------------------------------------

  A  TO ANALYZE DATA  ESC TO QUIT

  ?  FOR HELP SCREEN  /  CHANGE PARMS

  Q  FOR NEXT TRACK   SPACE TO RE-READ

                 --^--

Disk Fixer
  ["O" -> "Input/Output Control"]
    "CHECKSUM ENABLED" -> "NO"
  T00,S00 readable
  T00,S0D readable
  T00,S0E readable
  nothing else

Why didn't COPYA work?
  not a 16-sector disk (or maybe a
   wildly non-standard one)

Why didn't Locksmith FDB work?
  ditto

Why didn't my EDD copy work?
  I don't know. Probably a nibble check
  in the first .SYSTEM file (assuming
  this is really ProDOS as it claims).

Converting the disk to a standard
format will be a challenge. Advanced
Demuffin requires a DOS 3.3-shaped
RWTS, but this disk uses ProDOS (as far
as I can tell). Assuming the disk even
uses 16 sectors (and Copy ][+ just
can't see the structure), I might be
able to extract the RWTS from the
PRODOS file and build an RWTS to plug
into Advanced Demuffin. I've done that
successfully before, but it's finicky.
DOS 3.3 and ProDOS are very different
beasts.

Next steps:

  1. Boot trace to capture PRODOS file
     in memory
  2. Extract its RWTS routines to build
     a DOS 3.3-shaped RWTS file
  3. Convert the disk to a standard
     format with Advanced Demuffin
  4. Patch the bootloader and/or the
     PRODOS file to be able to read
     a standard format disk
  5. Find and bypass the nibble check
  6. Declare victory (*)

(*) go to the home gym

                   ~

               Chapter 1
      In Which We Brag About Our
           Humble Beginnings


I have two floppy drives, one in slot 6
and the other in slot 5. My "work disk"
(in slot 5) runs Diversi-DOS 64K, which
is compatible with Apple DOS 3.3 but
relocates most of DOS to the language
card on boot. This frees up most of
main memory (only using a single page
at $BF00..$BFFF), which is useful for
loading large files or examining code
that lives in areas typically reserved
for DOS.

[S6,D1=original disk]
[S5,D1=my work disk]

The floppy drive firmware code at $C600
is responsible for aligning the drive
head and reading sector 0 of track 0
into main memory at $0800. Because the
drive can be connected to any slot, the
firmware code can't assume it's loaded
at $C600. If the floppy drive card were
removed from slot 6 and reinstalled in
slot 5, the firmware code would load at
$C500 instead.

To accommodate this, the firmware does
some fancy stack manipulation to detect
where it is in memory (which is a neat
trick, since the 6502 program counter
is not generally accessible). However,
due to space constraints, the detection
code only cares about the lower 4 bits
of the high byte of its own address.

Stay with me, this is all about to come
together and go boom.

$C600 (or $C500, or anywhere in $Cx00)
is read-only memory. I can't change it,
which means I can't stop it from
transferring control to the boot sector
of the disk once it's in memory. BUT!
The disk firmware code works unmodified
at any address. Any address that ends
with $x600 will boot slot 6, including
$B600, $A600, $9600, &c.

; copy drive firmware to $9600
*9600<C600.C6FFM

; and execute it
*9600G
...reboots slot 6, loads game...

Now then:

]PR#5
...
]CALL -151

*9600<C600.C6FFM

*96F8L

96F8-   4C 01 08    JMP   $0801

That's where the disk controller ROM
code ends and the on-disk code begins.
But $9600 is part of read/write memory.
I can change it at will. So I can
interrupt the boot process after the
drive firmware loads the boot sector
from the disk but before it transfers
control to the disk's bootloader.

; instead of jumping to on-disk code,
; copy boot sector to higher memory so
; it survives a reboot
96F8-   A0 00       LDY   #$00
96FA-   B9 00 08    LDA   $0800,Y
96FD-   99 00 28    STA   $2800,Y
9700-   C8          INY
9701-   D0 F7       BNE   $96FA

; turn off slot 6 drive motor
9703-   AD E8 C0    LDA   $C0E8

; reboot to my work disk in slot 5
9706-   4C 00 C5    JMP   $C500

*BSAVE TRACE0,A$9600,L$109
*9600G
...reboots slot 6...
...reboots slot 5...

]BSAVE OBJ.0800-08FF,A$2800,L$100

Now we get to(*) trace the boot process
one sector, one page, one instruction
at a time.

(*) If you replace the words "need to"
    with the words "get to," life
    becomes amazing.

                   ~

               Chapter 2
        In Which We Will Not Be
    Going To The Gym Any Time Soon,
     For Several Unrelated Reasons


]CALL -151
*800<2800.28FFM
*801L

; set up $801 with an "RTS" (probably
; so we can JSR $C65C later to read
; sectors)
0801-   A9 60       LDA   #$60
0803-   8D 01 08    STA   $0801

; save slot (x16)
0806-   86 43       STX   $43
0808-   86 2B       STX   $2B

; munge slot into $C6 form and store it
080A-   8A          TXA
080B-   4A          LSR
080C-   4A          LSR
080D-   4A          LSR
080E-   4A          LSR
080F-   09 C0       ORA   #$C0
0811-   8D 38 08    STA   $0838

; set reset vector
0814-   A0 CE       LDY   #$CE
0816-   A9 08       LDA   #$08
0818-   8C F2 03    STY   $03F2
081B-   8D F3 03    STA   $03F3
081E-   A9 AD       LDA   #$AD
0820-   8D F4 03    STA   $03F4

; initialize something in zero page
0823-   A9 00       LDA   #$00
0825-   85 09       STA   $09
0827-   85 03       STA   $03

; increment physical sector number
0829-   E6 3D       INC   $3D

; read a sector
082B-   20 36 08    JSR   $0836

; decrement sector count
082E-   CE 39 08    DEC   $0839

; loop back to read more sectors
0831-   D0 F6       BNE   $0829

; or continue down below
0833-   4C 40 08    JMP   $0840
0836-   4C 5C C6    JMP   $C65C
0839-  [02]
083A-  ["PRODOS"]

; execution continues here after all
; sectors are read
0840-   A9 02       LDA   #$02
0842-   85 02       STA   $02
0844-   A9 0C       LDA   #$0C
0846-   85 27       STA   $27

; don't know what this does yet
0848-   20 34 09    JSR   $0934

This is where I get to interrupt the
boot, to see what ends up at $900 (and
$A00) from initial sector read loop.

*9600<C600.C6FFM

; set up callback at $0840 after sector
; read loop exits
96F8-   A9 4C       LDA   #$4C
96FA-   8D 40 08    STA   $0840
96FD-   A9 0A       LDA   #$0A
96FF-   8D 41 08    STA   $0841
9702-   A9 97       LDA   #$97
9704-   8D 42 08    STA   $0842

; start the boot
9707-   4C 01 08    JMP   $0801

; callback is here -- copy 3 pages to
; graphics page so they survive a
; reboot
970A-   A2 03       LDX   #$03
970C-   A0 00       LDY   #$00
970E-   B9 00 08    LDA   $0800,Y
9711-   99 00 28    STA   $2800,Y
9714-   C8          INY
9715-   D0 F7       BNE   $970E
9717-   EE 10 97    INC   $9710
971A-   EE 13 97    INC   $9713
971D-   CA          DEX
971E-   D0 EE       BNE   $970E

; turn off slot 6 drive motor
9720-   AD E8 C0    LDA   $C0E8

; reboot to my work disk
9723-   4C 00 C5    JMP   $C500

*BSAVE TRACE1,A$9600,L$126
*9600G
...reboots slot 6...
...reboots slot 5...

]BSAVE OBJ.0800-0AFF,A$2800,L$300
]CALL -151
*800<2800.2AFFM
*934L
.
. actually boring, it's just setting up
. a write translate table (but at least
. now we know, and we have the rest of
. the code in memory)
.

Continuing at $084B...

; subroutine appears to read a sector
; into the address pointed to by ($26)
; (not shown)
084B-   20 EF 08    JSR   $08EF

; look for PRODOS file in disk catalog
; (string at $0839 spells "PRODOS")
084E-   A9 04       LDA   #$04
0850-   85 00       STA   $00
0852-   A9 0C       LDA   #$0C
0854-   85 01       STA   $01
0856-   A5 00       LDA   $00
0858-   18          CLC
0859-   69 27       ADC   #$27
085B-   85 00       STA   $00
085D-   B0 6F       BCS   $08CE
085F-   A0 06       LDY   #$06
0861-   B1 00       LDA   ($00),Y
0863-   D9 39 08    CMP   $0839,Y
0866-   D0 EE       BNE   $0856
0868-   88          DEY
0869-   D0 F6       BNE   $0861

; get block info for PRODOS file
086B-   B1 00       LDA   ($00),Y
086D-   48          PHA
086E-   A0 10       LDY   #$10
0870-   B1 00       LDA   ($00),Y
0872-   C9 FF       CMP   #$FF
0874-   D0 58       BNE   $08CE
0876-   C8          INY
0877-   B1 00       LDA   ($00),Y
0879-   85 02       STA   $02
087B-   C8          INY
087C-   B1 00       LDA   ($00),Y
087E-   85 03       STA   $03
0880-   A9 FF       LDA   #$FF
0882-   85 07       STA   $07
0884-   A9 00       LDA   #$00
0886-   85 26       STA   $26
0888-   85 00       STA   $00
088A-   A0 1E       LDY   #$1E
088C-   68          PLA
088D-   C9 26       CMP   #$26
088F-   F0 0B       BEQ   $089C

; load data at $2000
0891-   A0 20       LDY   #$20
0893-   84 27       STY   $27

; read it
0895-   20 EF 08    JSR   $08EF

; carry clear on success
0898-   90 1F       BCC   $08B9

; carry set on failure
089A-   B0 32       BCS   $08CE

; loop to read the rest of the file
089C-   84 27       STY   $27
089E-   84 01       STY   $01
08A0-   20 EF 08    JSR   $08EF
08A3-   B0 29       BCS   $08CE
08A5-   E6 07       INC   $07
08A7-   A4 07       LDY   $07
08A9-   B1 00       LDA   ($00),Y
08AB-   85 02       STA   $02
08AD-   E6 01       INC   $01
08AF-   B1 00       LDA   ($00),Y
08B1-   85 03       STA   $03
08B3-   C6 01       DEC   $01
08B5-   11 00       ORA   ($00),Y
08B7-   D0 E7       BNE   $08A0

; execution continues here after all
; sectors are read successfully --
; turn off drive motor
08B9-   BD 88 C0    LDA   $C088,X

; set reset vector
08BC-   A2 00       LDX   #$00
08BE-   A0 57       LDY   #$57
08C0-   A9 F2       LDA   #$F2
08C2-   8E F2 03    STX   $03F2
08C5-   8C F3 03    STY   $03F3
08C8-   8D F4 03    STA   $03F4

; jump to the beginning of PRODOS file
08CB-   4C 00 20    JMP   $2000

; any failure ends up here
08CE-   E6 27       INC   $27
08D0-   A0 00       LDY   #$00
08D2-   A6 2B       LDX   $2B

; turn off drive motor
08D4-   BD 88 C0    LDA   $C088,X

; wipe memory and never return
08D7-   20 DD 08    JSR   $08DD
08DA-   4C DA 08    JMP   $08DA
08DD-   A9 60       LDA   #$60
08DF-   91 26       STA   ($26),Y
08E1-   99 00 09    STA   $0900,Y
08E4-   99 00 0A    STA   $0A00,Y
08E7-   88          DEY
08E8-   D0 F5       BNE   $08DF
08EA-   C6 27       DEC   $27
08EC-   4C DF 08    JMP   $08DF

So, it really is loading ProDOS, albeit
in its own special way. $08CB jumps to
the code loaded from the PRODOS file at
$2000.

                   ~

               Chapter 3
   In Which We Play That Funky Music
              'Til We Die


Let's capture this funky version of
ProDOS and see what mischief awaits us.

*9600<C600.C6FFM

; save all flags and registers
96F8-   08          PHP
96F9-   48          PHA
96FA-   8A          TXA
96FB-   48          PHA
96FC-   98          TYA
96FD-   48          PHA

; fill $2000..$95FF with "FD" bytes so
; I can tell how big the PRODOS file is
; later
96FE-   A2 76       LDX   #$76
9700-   A0 00       LDY   #$00
9702-   A9 FD       LDA   #$FD
9704-   99 00 20    STA   $2000,Y
9707-   C8          INY
9708-   D0 FA       BNE   $9704
970A-   EE 06 97    INC   $9706
970D-   CA          DEX
970E-   D0 F4       BNE   $9704

; set up the callback after PRODOS file
; is loaded
9710-   A9 23       LDA   #$23
9712-   8D CC 08    STA   $08CC
9715-   A9 97       LDA   #$97
9717-   8D CD 08    STA   $08CD

; restore registers and flags
971A-   68          PLA
971B-   A8          TAY
971C-   68          PLA
971D-   AA          TAX
971E-   68          PLA
971F-   28          PLP

; start the boot
9720-   4C 01 08    JMP   $0801

; turn off slot 6 drive motor
9723-   AD E8 C0    LDA   $C0E8

; reboot to my work disk (PRODOS file
; loads at $2000, so no relocation is
; necessary)
9726-   4C 00 C5    JMP   $C500

*BSAVE TRACE.PRODOS,A$9600,L$129

*BRUN TRACE.PRODOS
...reboots slot 6...
...reboots slot 5...

]CALL -151

[perusing memory, starting at $2000]

It looks like $5A00 is the first page
that still has repeated $FD bytes.

*5A-20
=3A
*BSAVE OBJ.2000-59FF,A$2000,L$3A00

Scanning through memory, I found the
RWTS code. (Sorry, no magic here. It
can be in a number of places, depending
on the version of ProDOS. And this is
*not* a standard version of ProDOS.)

The RWTS is... odd. Here, for example,
is the routine that reads the address
field (relocated into the language card
at $D316 by the time it's used):

*5316L

5316-   A6 3E       LDX   $3E
5318-   A0 03       LDY   #$03
531A-   8C E8 D4    STY   $D4E8
531D-   8C F0 D4    STY   $D4F0
5320-   84 3F       STY   $3F
5322-   A0 02       LDY   #$02
5324-   CE F0 D4    DEC   $D4F0
5327-   D0 05       BNE   $532E
5329-   CE E8 D4    DEC   $D4E8
532C-   F0 3A       BEQ   $5368

; loop will match "CA AA A9" (that's
; what's at $D4D0, a.k.a. $54D0)
532E-   BD 8C C0    LDA   $C08C,X
5331-   10 FB       BPL   $532E
5333-   D9 D0 D4    CMP   $D4D0,Y
5336-   D0 EA       BNE   $5322
5338-   88          DEY
5339-   10 F3       BPL   $532E

; now decode the actual address field
533B-   A9 00       LDA   #$00
533D-   F0 03       BEQ   $5342
533F-   99 A7 D4    STA   $D4A7,Y

; read only one nibble
5342-   BC 8C C0    LDY   $C08C,X
5345-   10 FB       BPL   $5342

; rolling checkum in A
5347-   59 00 D4    EOR   $D400,Y
534A-   A4 3F       LDY   $3F
534C-   C6 3F       DEC   $3F

; branch back to store this address
; field data in $D4A7,Y
534E-   10 EF       BPL   $533F

; rolling checksum must match or we
; start over
5350-   A8          TAY
5351-   D0 15       BNE   $5368

; then match $AA as a 1-nibble epilogue
5353-   BD 8C C0    LDA   $C08C,X
5356-   10 FB       BPL   $5353
5358-   C9 AA       CMP   #$AA
535A-   D0 0C       BNE   $5368

; munge one of the address field values
; into the Y register on exit (not sure
; which one)
535C-   AD A9 D4    LDA   $D4A9
535F-   4A          LSR
5360-   4A          LSR
5361-   A8          TAY

; munge another value into A
5362-   AD AA D4    LDA   $D4AA
5365-   4A          LSR
5366-   4A          LSR
5367-   60          RTS
5368-   38          SEC
5369-   60          RTS

And here is the heart of the RWTS, the
routine that matches the data prologue
then converts the data field of nibbles
to bytes in memory:

*536AL

; set up slot-specific addresses for
; reading the data latch (normal)
536A-   8A          TXA
536B-   09 8C       ORA   #$8C
536D-   8D B0 D3    STA   $D3B0
5370-   8D BD D3    STA   $D3BD
5373-   8D CF D3    STA   $D3CF
5376-   8D E1 D3    STA   $D3E1
5379-   8D F6 D3    STA   $D3F6
537C-   A0 20       LDY   #$20
537E-   88          DEY
537F-   30 E7       BMI   $5368

; match "CA D5 A9" data prologue
; with some... interesting variations
5381-   BD 8C C0    LDA   $C08C,X
5384-   10 FB       BPL   $5381
5386-   C9 CA       CMP   #$CA
5388-   D0 F4       BNE   $537E
538A-   2C A8 D4    BIT   $D4A8   ; odd
538D-   BD 8C C0    LDA   $C08C,X
5390-   10 FB       BPL   $538D
5392-   C9 D5       CMP   #$D5
5394-   D0 F0       BNE   $5386
5396-   50 03       BVC   $539B   ; odd
5398-   BD 8D C0    LDA   $C08D,X ; !!!
539B-   BD 8C C0    LDA   $C08C,X
539E-   10 FB       BPL   $539B
53A0-   C9 A9       CMP   #$A9
53A2-   F0 07       BEQ   $53AB
53A4-   88          DEY
53A5-   10 F4       BPL   $539B
53A7-   D0 BF       BNE   $5368
53A9-   30 7E       BMI   $5429

; convert nibbles to bytes
53AB-   A0 54       LDY   #$54
53AD-   A9 00       LDA   #$00
53AF-   AE 8C C0    LDX   $C08C
53B2-   10 FB       BPL   $53AF
53B4-   5D 00 D4    EOR   $D400,X
53B7-   84 3F       STY   $3F
53B9-   29 FC       AND   #$FC
53BB-   AA          TAX
...[omitted for brevity]

; match $AA for data epilogue
5420-   BD 8C C0    LDA   $C08C,X
5423-   10 FB       BPL   $5420
5425-   C9 AA       CMP   #$AA
5427-   F0 16       BEQ   $543F
5429-   38          SEC
542A-   60          RTS
...
543F-   18          CLC
5440-   60          RTS

I won't do a side-by-side comparison,
but this is all completely different
from standard ProDOS. I don't just
mean the address prologue. Even the
routine that converts nibbles to bytes
is different.

Now what I saw in the nibble editor
makes slightly more sense:

                 --v--

   COPY ][ PLUS BIT COPY PROGRAM 8.4
(C) 1982-9 CENTRAL POINT SOFTWARE, INC.
---------------------------------------

TRACK: 03  START: 1800  LENGTH: 3DFF

18F8: F4 96 CB FF 9B 9B AA D5   VIEW
1900: FE FF FE FF FF F9 CF D3
1908: F3 99 E6 99 E6 99 E6 99
1910: E6 99 E6 99 E6 99 E6 99
1918: CA AA A9 9B B2 AF 96 AA
      ^^^^^^^^ ^^^^^^^^^^^^^^ address
 address prologue              field


1920: D5 FC 99 E6 99 E6 99 E6
            ^^^^^^^^^^^^^^^^^
            weird sync bytes

1928: 99 E6 99 E6 99 E6 CA D5
                        ^^^^^
                         data

1930: A9 AE FA F3 9A 96 B7 DE
      ^^ ^^^^^^^^^^^^^^^^^^^^
prologue    data field...

1938: F3 96 ED 96 ED F5 B9 9A

                 --^--

Porting this to a DOS 3.3-shaped RWTS
is not going to be feasible. This is
not just a matter of different prologue
or epilogue bytes; the entire nibble-
to-byte conversion scheme has been
rewritten. I need to rethink my next
steps.

This disk is, at some level, "ProDOS."
It has a custom bootloader to find and
load the PRODOS file into memory; it
has what appears to be an entirely
rewritten floppy device driver. It also
has an explicit protection check
somewhere that I haven't found yet.

But it's not entirely custom. About 90%
of this file is identical to ProDOS
(version 1.1.1, as advertised on the
standard ProDOS title screen that it
displays during boot). If I could
somehow inject a clean, working version
of BASIC.SYSTEM and get this PRODOS
file to load that instead of the
original program (but without loading
the STARTUP file), maybe I could see
the files and copy them to a standard
disk.

Next steps:

  1. Trace PRODOS file
  2. Inject clean BASIC.SYSTEM into
     memory
  3. Copy each file off the disk

                   ~

               Chapter 4
    In Which All RWTSen are Equal,
  But Some Are More Equal Than Others


[S7,D1=ProDOS hard drive, "A4AMCRACK"]

[Copy ][+ 8.4]
  --> COPY
    --> FILE
      --> from SLOT 7, DRIVE 1
      -->   to SLOT 5, DRIVE 1
        --> BASIC.SYSTEM

OK, now I have a clean copy of the
ProDOS BASIC.SYSTEM file on my DOS 3.3-
based work disk. I'll get back to that.

]PR#5
...
]BLOAD OBJ.2000-59FF,A$2000
]CALL -151

*2000L
.
. nothing unusual, until...
.
; set up to read block 2 into $0C00
; (this is the ProDOS disk catalog)
218F-   A2 00       LDX   #$00
2191-   86 14       STX   $14
2193-   A0 02       LDY   #$02
2195-   A9 0C       LDA   #$0C
2197-   85 15       STA   $15
2199-   8D 07 22    STA   $2207
219C-   8C 08 22    STY   $2208
219F-   8E 09 22    STX   $2209

; raw disk read (MLI $80)
21A2-   20 00 BF    JSR   $BF00
21A5-  [80 04 22]

; on failure, jump to The Badlands
21A8-   D0 19       BNE   $21C3

; check if we've read all the blocks of
; the disk catalog into memory
21AA-   A0 03       LDY   #$03
21AC-   B1 14       LDA   ($14),Y
21AE-   AA          TAX
21AF-   88          DEY
21B0-   11 14       ORA   ($14),Y
21B2-   F0 0C       BEQ   $21C0
21B4-   B1 14       LDA   ($14),Y
21B6-   A8          TAY
21B7-   A5 15       LDA   $15
21B9-   18          CLC
21BA-   69 02       ADC   #$02
21BC-   C9 14       CMP   #$14
21BE-   90 D7       BCC   $2197

; success path continues at $5800
21C0-   4C 00 58    JMP   $5800

; failure path ends up here
21C3-   4C 00 57    JMP   $5700

*5700L

; relocate this to $0800
5700-   A2 80       LDX   #$80
5702-   BD 0E 57    LDA   $570E,X
5705-   9D 00 08    STA   $0800,X
5708-   CA          DEX
5709-   10 F7       BPL   $5702

; and jump there
570B-   4C 00 08    JMP   $0800

; wipe all memory
570E-   2C 89 C0    BIT   $C089
5711-   2C 89 C0    BIT   $C089
5714-   A2 1F       LDX   #$1F
5716-   A0 00       LDY   #$00
5718-   99 00 09    STA   $0900,Y
571B-   99 00 20    STA   $2000,Y
571E-   99 00 40    STA   $4000,Y
5721-   99 00 60    STA   $6000,Y
5724-   99 00 80    STA   $8000,Y
5727-   99 00 A0    STA   $A000,Y
572A-   99 00 D0    STA   $D000,Y

; and make a sound while doing it
572D-   AD 30 C0    LDA   $C030
5730-   88          DEY
5731-   D0 E5       BNE   $5718
5733-   EE 0C 08    INC   $080C
5736-   EE 0F 08    INC   $080F
5739-   EE 12 08    INC   $0812
573C-   EE 15 08    INC   $0815
573F-   EE 18 08    INC   $0818
5742-   EE 1B 08    INC   $081B
5745-   EE 1E 08    INC   $081E
5748-   CA          DEX
5749-   10 CD       BPL   $5718
574B-   8D F2 03    STA   $03F2
574E-   8D F3 03    STA   $03F3
5751-   2C 8A C0    BIT   $C08A

; and reboot
5754-   6C FC FF    JMP   ($FFFC)

Well, let's try not to end up there!

If we read the catalog successfully,
execution continues at $5800.

*5800L

5800-   A2 4B       LDX   #$4B
5802-   86 02       STX   $02
5804-   2C 81 C0    BIT   $C081
5807-   2C 81 C0    BIT   $C081
580A-   A9 D1       LDA   #$D1
580C-   8D 04 D1    STA   $D104

; set reset vector
580F-   A2 F6       LDX   #$F6
5811-   A0 BF       LDY   #$BF
5813-   A9 1A       LDA   #$1A
5815-   8E F2 03    STX   $03F2
5818-   8C F3 03    STY   $03F3
581B-   8D F4 03    STA   $03F4

; reset drive stepper motors
581E-   A5 43       LDA   $43
5820-   29 70       AND   #$70
5822-   85 3E       STA   $3E
5824-   AA          TAX
5825-   BD 80 C0    LDA   $C080,X
5828-   BD 82 C0    LDA   $C082,X
582B-   BD 84 C0    LDA   $C084,X
582E-   BD 86 C0    LDA   $C086,X

; then turn on drive motor manually
; (this is never not suspicious)
5831-   BD 89 C0    LDA   $C089,X
5834-   24 43       BIT   $43
5836-   10 01       BPL   $5839
5838-   E8          INX
5839-   BD 8A C0    LDA   $C08A,X

; wait loop ($58A5 is just an RTS)
583C-   A9 00       LDA   #$00
583E-   AA          TAX
583F-   A8          TAY
5840-   20 A5 58    JSR   $58A5
5843-   88          DEY
5844-   D0 FA       BNE   $5840
5846-   CA          DEX
5847-   D0 F7       BNE   $5840

; ($14) is an address pointer maybe?
5849-   85 44       STA   $44
584B-   A9 14       LDA   #$14
584D-   85 45       STA   $45

; read/write access to RAM bank 1
584F-   2C 8B C0    BIT   $C08B
5852-   2C 8B C0    BIT   $C08B

; don't know what this does yet
5855-   20 03 D0    JSR   $D003
5858-   A2 03       LDX   #$03
585A-   86 00       STX   $00
585C-   86 01       STX   $01
585E-   A2 15       LDX   #$15
5860-   86 03       STX   $03
5862-   C6 03       DEC   $03
5864-   30 12       BMI   $5878

; nor this
5866-   20 0C D0    JSR   $D00C
5869-   B0 F7       BCS   $5862
586B-   C0 06       CPY   #$06
586D-   D0 F3       BNE   $5862

; nor any of this
586F-   20 0F D0    JSR   $D00F
5872-   90 19       BCC   $588D
5874-   C6 01       DEC   $01
5876-   10 E6       BPL   $585E
5878-   A6 02       LDX   $02
587A-   30 26       BMI   $58A2
587C-   A0 12       LDY   #$12
587E-   BD A6 58    LDA   $58A6,X
5881-   99 96 D3    STA   $D396,Y
5884-   CA          DEX
5885-   88          DEY
5886-   10 F6       BPL   $587E
5888-   86 02       STX   $02
588A-   4C 58 58    JMP   $5858
588D-   C6 00       DEC   $00
588F-   10 CD       BPL   $585E
5891-   A5 01       LDA   $01
5893-   C9 03       CMP   #$03
5895-   D0 E1       BNE   $5878

; success path falls through to here
; (I think)
5897-   A6 3E       LDX   $3E

; turn off drive motor
5899-   BD 88 C0    LDA   $C088,X

; switch to ROM
589C-   2C 8A C0    BIT   $C08A

; continue with "stage 2" loader (to
; launch .SYSTEM file, probably)
589F-   4C 00 08    JMP   $0800

; failure path ends up here
58A2-   4C F6 BF    JMP   $BFF6

*BFF6L

BFF6-   2C 80 C0    BIT   $C080
BFF9-   4C 00 D1    JMP   $D100

I'm guessing that $D100 ends up
executing the code that started out at
$5700, a.k.a. The Badlands.

By the time execution reaches $589F
(the success path), ProDOS has done
everything it's going to do to relocate
itself into the language card, and it's
time to find the first .SYSTEM file and
load it. But that file is loaded at
$2000, so ProDOS moves its "stage 2"
code to $800 to avoid memory conflicts.

Oh, and it's modified the RWTS in
memory a number of times. How many? I'm
not sure yet.

I get to interrupt the boot to see what
evil lurks at $D003, $D00C, and $D00F.

*9600<C600.C6FFM

; set up callback #1 after PRODOS file
; is loaded
96F8-   A9 4C       LDA   #$4C
96FA-   8D CB 08    STA   $08CB
96FD-   A9 0A       LDA   #$0A
96FF-   8D CC 08    STA   $08CC
9702-   A9 97       LDA   #$97
9704-   8D CD 08    STA   $08CD

; start the boot
9707-   4C 01 08    JMP   $0801

; (callback #1) set up callback #2 just
; before switching on RAM bank 1
970A-   A9 4C       LDA   #$4C
970C-   8D 4F 58    STA   $584F
970F-   A9 1C       LDA   #$1C
9711-   8D 50 58    STA   $5850
9714-   A9 97       LDA   #$97
9716-   8D 51 58    STA   $5851

; continue the boot
9719-   4C 00 20    JMP   $2000

; (callback #2) switch to RAM bank 1
; and dump the entire contents into
; main memory
971C-   2C 8B C0    BIT   $C08B
971F-   2C 8B C0    BIT   $C08B
9722-   A2 30       LDX   #$30
9724-   A0 00       LDY   #$00
9726-   B9 00 D0    LDA   $D000,Y
9729-   99 00 20    STA   $2000,Y
972C-   C8          INY
972D-   D0 F7       BNE   $9726
972F-   EE 28 97    INC   $9728
9732-   EE 2B 97    INC   $972B
9735-   CA          DEX
9736-   D0 EE       BNE   $9726

; switch back to ROM
9738-   2C 82 C0    BIT   $C082

; reboot to my work disk
973B-   4C 00 C5    JMP   $C500

*BSAVE TRACE.D003,A$9600,L$13E
*9600G
...reboots slot 6...
...reboots slot 5...

]BSAVE OBJ.D000-FFFF,A$2000,L$3000
]CALL -151
*2003L

2003-   4C E5 D2    JMP   $D2E5

*22E5L

; This just sets up the absolute
; addresses in the RWTS so it can put
; the sector data in-place in its final
; memory destination. Perfectly normal.
; By the way, ($44) points to $1400;
; that was initialized at $5849, just
; before this call.
22E5-   A5 44       LDA   $44
22E7-   A4 45       LDY   $45
22E9-   8D CC D3    STA   $D3CC
22EC-   8C CD D3    STY   $D3CD
22EF-   8D 12 D4    STA   $D412
22F2-   8C 13 D4    STY   $D413
22F5-   18          CLC
22F6-   69 55       ADC   #$55
22F8-   90 01       BCC   $22FB
22FA-   C8          INY
22FB-   85 3A       STA   $3A
22FD-   84 3B       STY   $3B
22FF-   8D DE D3    STA   $D3DE
2302-   8C DF D3    STY   $D3DF
2305-   18          CLC
2306-   69 55       ADC   #$55
2308-   90 01       BCC   $230B
230A-   C8          INY
230B-   85 3C       STA   $3C
230D-   84 3D       STY   $3D
230F-   8D F0 D3    STA   $D3F0
2312-   8C F1 D3    STY   $D3F1
2315-   60          RTS

*200CL

200C-   4C 16 D3    JMP   $D316

OK, I know that routine reads the next
available address field. (It was
originally at $5316; I already traced
it earlier.)

*200FL

200F-   4C 6A D3    JMP   $D36A

This routine was originally at $536A.
It reads the data field.

Now this entire loop makes more sense.
It's literally copying different chunks
of code into the middle of the RWTS and
trying to read the same sector over and
over with each variation. OK, when I
say that out loud, that doesn't really
make a whole lot of sense. But let's
list it again and sprinkle some more
comments around.

The main loop starts at $5858. There
are 4 counters, $00, $01, $02, and $03.
$00 is the number of times we've tried
to read the sector (starts at 3 and is
decremented). $01 is a death counter
(starts at 3 and is checked after each
reads, but any change is fatal). $02 is
used as an index for copying $13-byte
chunks of code into the RWTS. When it
goes negative, we've tried all of the
RWTS variations. $02 starts at $4B (set
at $5800). $03 is a death counter for
finding the sector on the track, which
is reset after each successful read.

5858-   A2 03       LDX   #$03
585A-   86 00       STX   $00
585C-   86 01       STX   $01

; $03 is an inner loop death counter
; for finding the proper sector
585E-   A2 15       LDX   #$15
5860-   86 03       STX   $03
5862-   C6 03       DEC   $03

; if $03 goes negative, give up
5864-   30 12       BMI   $5878

; read next available address field
5866-   20 0C D0    JSR   $D00C

; if that returned an error, loop back
; and try again (decrements $03)
5869-   B0 F7       BCS   $5862

; After the routine at $D00C, the Y
; register has an address field value
; (guessing this is a sector number)
586B-   C0 06       CPY   #$06

; not the right sector, try again
586D-   D0 F3       BNE   $5862

; yes, now read data field
586F-   20 0F D0    JSR   $D00F

; if that worked, branch forward
5872-   90 19       BCC   $588D

; if the read failed, decrement the
; read-data death counter and try again
5874-   C6 01       DEC   $01
5876-   10 E6       BPL   $585E

; if we've tried all variations, give
; up entirely, otherwise fall through
5878-   A6 02       LDX   $02
587A-   30 26       BMI   $58A2

; copy $13 bytes of code into the
; middle of the RWTS routine(!)
587C-   A0 12       LDY   #$12
587E-   BD A6 58    LDA   $58A6,X
5881-   99 96 D3    STA   $D396,Y
5884-   CA          DEX
5885-   88          DEY
5886-   10 F6       BPL   $587E

; store the index pointer so the next
; time through the loop, we copy a
; different chunk of code into the
; middle of the RWTS routine(!)
5888-   86 02       STX   $02

; start over with this RWTS variation
588A-   4C 58 58    JMP   $5858

; execution continues here (from $5872)
; after a successful sector read --
; decrement the sector read counter and
; try again
588D-   C6 00       DEC   $00
588F-   10 CD       BPL   $585E

; all RWTS variations must work
5891-   A5 01       LDA   $01
5893-   C9 03       CMP   #$03
5895-   D0 E1       BNE   $5878

; turn off the drive motor
5897-   A6 3E       LDX   $3E
5899-   BD 88 C0    LDA   $C088,X

; switch to ROM
589C-   2C 8A C0    BIT   $C08A

; continue with "stage 2" loader (to
; launch .SYSTEM file, presumably)
589F-   4C 00 08    JMP   $0800

; failure path ends up here
58A2-   4C F6 BF    JMP   $BFF6

Here are the four different variations
that it copies into the RWTS. Note that
the overflow bit will always be set by
the time this code is run, so the "BVC"
instruction burns 3 cycles but never
branches. Each variation burns a
different number of CPU cycles (listed
in the right margin) before checking
the third nibble of the data prologue.
The first one is left in memory after
the entire process is complete, to read
the rest of the disk.

#1:

58DF-   50 05       BVC   $58E6    | 3
58E1-   BD 8D C0    LDA   $C08D,X  | 4
58E4-   48          PHA            | 3
58E5-   68          PLA            | 4
58E6-   BD 8C C0    LDA   $C08C,X
58E9-   10 FB       BPL   $58E6
58EB-   C9 A9       CMP   #$A9
58ED-   F0 05       BEQ   $58F4
58EF-   88          DEY
58F0-   10 F4       BPL   $58E6

#2:

58CC-   50 05       BVC   $58D3    | 3
58CE-   BD 8D C0    LDA   $C08D,X  | 4
58D1-   EA          NOP            | 2
58D2-   EA          NOP            | 2
58D3-   BD 8C C0    LDA   $C08C,X
58D6-   10 FB       BPL   $58D3
58D8-   C9 A9       CMP   #$A9
58DA-   F0 05       BEQ   $58E1
58DC-   88          DEY
58DD-   10 F4       BPL   $58D3

#3:

58B9-   50 04       BVC   $58BF    | 3
58BB-   BD 8D C0    LDA   $C08D,X  | 4
58BE-   EA          NOP            | 2
58BF-   BD 8C C0    LDA   $C08C,X
58C2-   10 FB       BPL   $58BF
58C4-   C9 A9       CMP   #$A9
58C6-   F0 06       BEQ   $58CE
58C8-   88          DEY
58C9-   10 F4       BPL   $58BF
58CB-   EA          NOP

#4:

58A6-   50 03       BVC   $58AB    | 3
58A8-   BD 8D C0    LDA   $C08D,X  | 4
58AB-   BD 8C C0    LDA   $C08C,X
58AE-   10 FB       BPL   $58AB
58B0-   C9 A9       CMP   #$A9
58B2-   F0 07       BEQ   $58BB
58B4-   88          DEY
58B5-   D0 F4       BNE   $58AB
58B7-   EA          NOP
58B8-   EA          NOP

None of these timing variations work on
my EDD bit copy, because they all need
some timing bits between the second and
third nibble of the data prologue, and
EDD doesn't preserve those by default.
There's a specific protection check,
but mainly just to gracefully deal with
the fact that the RWTS is only going to
be able to read the rest of the disk if
it contains uncopyable timing bits.
Every sector of the disk is designed to
foil bit copiers.

                   ~

               Chapter 5
         Prepare for Injection


Let's capture the "stage 2" code that
ends up at $0800, then we'll see what
we can do to inject BASIC.SYSTEM into
memory and launch it.

*9600<C600.C6FFM

; set up callback #1
96F8-   A9 4C       LDA   #$4C
96FA-   8D CB 08    STA   $08CB
96FD-   A9 0A       LDA   #$0A
96FF-   8D CC 08    STA   $08CC
9702-   A9 97       LDA   #$97
9704-   8D CD 08    STA   $08CD

; start the boot
9707-   4C 01 08    JMP   $0801

; (callback #1) set up callback #2
970A-   A9 4C       LDA   #$4C
970C-   8D 9F 58    STA   $589F
970F-   A9 1C       LDA   #$1C
9711-   8D A0 58    STA   $58A0
9714-   A9 97       LDA   #$97
9716-   8D A1 58    STA   $58A1

; continue the boot
9719-   4C 00 20    JMP   $2000

; (callback #2) copy stage 2 code from
; $0800 to graphics page so it survives
; a reboot
971C-   A2 18       LDX   #$18
971E-   A0 00       LDY   #$00
9720-   B9 00 08    LDA   $0800,Y
9723-   99 00 28    STA   $2800,Y
9726-   C8          INY
9727-   D0 F7       BNE   $9720
9729-   EE 22 97    INC   $9722
972C-   EE 25 97    INC   $9725
972F-   CA          DEX
9730-   D0 EE       BNE   $9720

; turn off slot 6 drive motor
9732-   AD E8 C0    LDA   $C0E8

; reboot to my work disk
9735-   4C 00 C5    JMP   $C500

*BSAVE TRACE2,A$9600,L$138
*9600G
...reboots slot 6...
...reboots slot 5...

]BSAVE OBJ.0800-14FF,A$2800,L$D00
]CALL -151

*800<2800.34FFM

*800L

; this is looking through the disk
; catalog (loaded at $0C00)
0800-   A9 0C       LDA   #$0C
0802-   85 11       STA   $11
0804-   A9 04       LDA   #$04
0806-   2C A5 10    BIT   $10A5
0809-   18          CLC
080A-   6D 23 0C    ADC   $0C23
080D-   85 10       STA   $10
080F-   B0 12       BCS   $0823
0811-   6D 23 0C    ADC   $0C23
0814-   90 0F       BCC   $0825
0816-   A5 11       LDA   $11
0818-   4A          LSR
0819-   90 0A       BCC   $0825
081B-   C9 09       CMP   #$09
081D-   F0 1E       BEQ   $083D
081F-   A9 04       LDA   #$04
0821-   85 10       STA   $10
0823-   E6 11       INC   $11
0825-   A0 10       LDY   #$10
0827-   A9 FF       LDA   #$FF
0829-   51 10       EOR   ($10),Y
082B-   D0 DA       BNE   $0807
082D-   A8          TAY
082E-   B1 10       LDA   ($10),Y
0830-   F0 D5       BEQ   $0807
0832-   29 0F       AND   #$0F
0834-   8D 80 02    STA   $0280
0837-   C9 08       CMP   #$08
0839-   90 CC       BCC   $0807
083B-   B0 03       BCS   $0840
083D-   F0 6E       BEQ   $08AD
083F-   00          BRK
0840-   A8          TAY

; $0965 contains the string ".SYSTEM",
; so this is checking whether this file
; ends with the string ".SYSTEM"
0841-   A2 06       LDX   #$06
0843-   B1 10       LDA   ($10),Y
0845-   5D 65 09    EOR   $0965,X
0848-   0A          ASL

; if not, loop to find the next file
0849-   D0 BC       BNE   $0807
084B-   88          DEY
084C-   CA          DEX
084D-   10 F4       BPL   $0843

; copy the filename into the buffer at
; $0280 and another buffer at $093B (I
; think the second one is used for
; error messages if things go wrong)
084F-   A0 00       LDY   #$00
0851-   C8          INY
0852-   B1 10       LDA   ($10),Y
0854-   99 80 02    STA   $0280,Y
0857-   09 80       ORA   #$80
0859-   99 3B 09    STA   $093B,Y
085C-   CC 80 02    CPY   $0280
085F-   D0 F0       BNE   $0851

; pad error message with spaces
0861-   A9 A0       LDA   #$A0
0863-   99 3C 09    STA   $093C,Y
0866-   98          TYA
0867-   69 13       ADC   #$13
0869-   8D 4F 09    STA   $094F

; open file (ProDOS MLI $C8)
086C-   20 00 BF    JSR   $BF00
086F-  [C8 50 09]
0872-   D0 46       BNE   $08BA

; get file EOF (MLI $D1)
0874-   20 00 BF    JSR   $BF00
0877-  [D1 56 09]
087A-   D0 3E       BNE   $08BA
087C-   AD 5A 09    LDA   $095A
087F-   D0 53       BNE   $08D4
0881-   AD 59 09    LDA   $0959
0884-   C9 98       CMP   #$98
0886-   B0 4C       BCS   $08D4
0888-   8D 60 09    STA   $0960
088B-   AD 58 09    LDA   $0958
088E-   8D 5F 09    STA   $095F

; read file (MLI $CA)
0891-   20 00 BF    JSR   $BF00
0894-  [CA 5B 09]
0897-   F0 06       BEQ   $089F
0899-   C9 56       CMP   #$56
089B-   F0 37       BEQ   $08D4
089D-   D0 1B       BNE   $08BA

; close file (MLI $CC)
089F-   20 00 BF    JSR   $BF00
08A2-  [CC 63 09]
08A5-   D0 13       BNE   $08BA
08A7-   AD 82 C0    LDA   $C082

; jump to beginning of loaded file
08AA-   4C 00 20    JMP   $2000

This is where I want to interrupt the
boot and inject my clean version of
BASIC.SYSTEM.

*BLOAD BASIC.SYSTEM,A$6000

*9600<C600.C6FFM

; set up callback #1
96F8-   A9 4C       LDA   #$4C
96FA-   8D CB 08    STA   $08CB
96FD-   A9 0A       LDA   #$0A
96FF-   8D CC 08    STA   $08CC
9702-   A9 97       LDA   #$97
9704-   8D CD 08    STA   $08CD

; start the boot
9707-   4C 01 08    JMP   $0801

; (callback #1) set up callback #2
970A-   A9 4C       LDA   #$4C
970C-   8D 9F 58    STA   $589F
970F-   A9 1C       LDA   #$1C
9711-   8D A0 58    STA   $58A0
9714-   A9 97       LDA   #$97
9716-   8D A1 58    STA   $58A1

; continue the boot
9719-   4C 00 20    JMP   $2000

; (callback #2) set up callback #3
971C-   A9 4C       LDA   #$4C
971E-   8D AA 08    STA   $08AA
9721-   A9 2E       LDA   #$2E
9723-   8D AB 08    STA   $08AB
9726-   A9 97       LDA   #$97
9728-   8D AC 08    STA   $08AC

; continue the boot
972B-   4C 00 08    JMP   $0800

; (callback #3) move BASIC.SYSTEM into
; place (I manually BLOADed this file
; already at $6000)
972E-   A2 28       LDX   #$28
9730-   A0 00       LDY   #$00
9732-   B9 00 60    LDA   $6000,Y
9735-   99 00 20    STA   $2000,Y
9738-   C8          INY
9739-   D0 F7       BNE   $9732
973B-   EE 34 97    INC   $9734
973E-   EE 37 97    INC   $9737
9741-   CA          DEX
9742-   D0 EE       BNE   $9732

; tell BASIC.SYSTEM not to look for a
; STARTUP file
9744-   A9 00       LDA   #$00
9746-   8D 06 20    STA   $2006

; continue the boot with the clean
; version of BASIC.SYSTEM
9749-   4C 00 20    JMP   $2000

*BSAVE TRACE3,A$9600,L$14C
*9600G
...reboots slot 6...
...displays ProDOS title page...
...clears screen...

            PRODOS BASIC 1.5
        COPYRIGHT APPLE  1983-92

]

Un-frickin-believable. It actually
worked.

                   ~

               Chapter 5
    In Which Our Adventure Comes To
  A Sudden But Satisfying Conclusion


]CAT

/TOWN

 NAME           TYPE  BLOCKS  MODIFIED

 PRODOS          SYS      30   9-OCT-86
*LOADER.SYSTEM   SYS      18  <NO DATE>
*TOWN.PACK       BIN      40  11-JUL-86
 TCH.OPT.FILE    BIN       1  11-JUL-86
*PROMPTS.IMG     BIN       1  11-JUL-86
*MLK.OBJ         BIN       4   9-MAY-86
*TCHWIN.OBJ      BIN       5   3-JUN-86
*KEY.OBJ         BIN       1   9-MAY-86
*TOUCHES.IMG     BIN       3  11-JUL-86
*T.O.            BIN      12  11-JUL-86
*MOVIE           BIN       5  11-JUL-86
*MOVIE.BIN       BIN      29  11-JUL-86
*ZOO             BIN       6  11-JUL-86
*ZOO.BIN         BIN      28  11-JUL-86
*HOTEL           BIN       6  11-JUL-86
*HOTEL.BIN       BIN      14  20-JAN-86
*ANIMAL          BIN       6  11-JUL-86
*HOUSE.PACK      BIN      18  11-JUL-86
*SAM             BIN       4  11-JUL-86
*SAM.BIN         BIN      20  30-DEC-85
*FACTORY         BIN       5  11-JUL-86
*FAC.BIN         BIN      17  11-JUL-86

BLOCKS FREE:    0     BLOCKS USED:  280

The custom floppy device driver is in
memory, and I have unfettered access to
the disk through a clean version of
BASIC.SYSTEM.

]PREFIX /TOWN

]BLOAD LOADER.SYSTEM,A$2000,TSYS
]CALL -151

*2000L

2000-   A9 00       LDA   #$00
2002-   85 02       STA   $02
2004-   A9 08       LDA   #$08
2006-   85 03       STA   $03
2008-   A9 00       LDA   #$00
200A-   85 00       STA   $00
200C-   A9 35       LDA   #$35
200E-   85 01       STA   $01
2010-   A2 0D       LDX   #$0D
2012-   A0 00       LDY   #$00
2014-   B1 00       LDA   ($00),Y
2016-   91 02       STA   ($02),Y
2018-   C8          INY
2019-   D0 F9       BNE   $2014
201B-   E6 01       INC   $01
201D-   E6 03       INC   $03
201F-   CA          DEX
2020-   D0 F2       BNE   $2014

Un. Fettered. Access.

But how do I copy all these files to a
standard disk? I could do it one at a
time -- LOAD and BLOAD work, so I could
simply load each file into memory and
reboot and save it.

But wait. ProDOS has separate device
drivers for floppies and hard drives.
Maybe...

[S7,D1=ProDOS hard drive, "A4AMCRACK"]

]PREFIX /A4AMCRACK
]CAT

/A4AMCRACK

 NAME           TYPE  BLOCKS  MODIFIED

 A2.DESKTOP      DIR       2  29-APR-22
*PRODOS          SYS      34  18-JAN-18
 NS.CLOCK.SYSTEM SYS       4  <NO DATE>
 RAM.DRV.SYSTEM  SYS       4  26-MAY-92
 PROSEL.SYSTEM   SYS       1   1-APR-88
 PROSEL          BIN      13  29-APR-22
 BASIC.SYSTEM    SYS      21  28-JUL-20
 APP             DIR       6   7-JUN-22
 GAME            DIR       1  29-APR-22
 UTIL            DIR       5  28-JUL-20
 PIX             DIR       4   9-AUG-18
 ARCHIVE         DIR       1   3-AUG-18
*CONFIG.RAMDRV   BAS       7   4-DEC-88
 RAM.DRIVE       BIN       3  16-MAY-17
 RAM.DRV         SYS       4  16-MAY-17
*RDLINE          CMD       4  15-SEP-87
 RAM.DRIVE.16    BIN       4  16-MAY-17
 RAM.DRV.16      SYS       4   6-JUN-19
 SLIDE           DIR       5  11-JAN-18
 TMP             DIR       5   8-APR-22
 STARTUP         BAS       1   3-AUG-20
 INCOMING        DIR       8   7-APR-22
 PASSPORT        DIR       1   1-DEC-21

BLOCKS FREE:40217     BLOCKS USED:25318

Not only do I have unfettered access to
the floppy disk, I have my entire hard
drive of utilities at my disposal.

]-/A4AMCRACK/APPLICATIONS/COPYIIPLUS8.4
/UTIL.SYSTEM
...launches Copy ][+...

  --> CREATE SUBDIRECTORY
    --> SLOT 7, DRIVE 1
      --> SUBDIRECTORY NAME:
          "TOWN"

  --> COPY
    --> FILES
      --> from SLOT 6, DRIVE 1
      -->   to SLOT 7, DRIVE 1,
            "TOWN" directory
        --> all files

It works. Copy ][+ uses the version of
ProDOS in memory, including the custom
floppy disk driver. As far as Copy ][+
is concerned, there's nothing unusual
about this disk or its files. Hooray
for abstractions!

Now that I have all the files off the
original disk, I can safely put it away
and never touch it again. (Whew. Good
riddance.)

[S6,D1=blank disk]

]PR#7

Using Copy ][+ again, I can recreate
the original disk with a clean copy of
PRODOS. I have a directory of all the
different versions of PRODOS, for just
such an occasion, which is a perfectly
normal thing to have on your hard drive
in 2017.

[Copy ][+ 8.4]
  --> FORMAT DISK
    --> PRODOS
      --> SLOT 6, DRIVE 1
        --> VOLUME NAME: TOWN

  --> COPY
    --> FILES
      --> from SLOT 7, DRIVE 1
      -->   to SLOT 6, DRIVE 1
        --> ARCHIVES/PRODOS1.1.1/PRODOS

  --> COPY
    --> FILES
      --> from SLOT 7, DRIVE 1,
            "TOWN" directory
      -->   to SLOT 6, DRIVE 1
        --> all files except PRODOS

]PR#6
...works...

Quod erat liberandum.

                   ~

               Epilogue


Scouring the custom version of ProDOS
(on my work disk as "OBJ.2000-59FF"), I
found this copyright message embedded
in an otherwise unused sector:

                 --v--

-------------- DISK EDIT --------------
TRACK $1A/SECTOR $0D/VOLUME $FE/BYTE$00
---------------------------------------
$00:>03<03 03 FF A0 A0 A0 A0    ....
$08: A0 A0 A0 A0 A0 A0 A0 A0
$10: A0 A0 A0 A0 44 65 76 69       Devi
$18: 63 65 20 43 6F 6E 74 72   ce Contr
$20: 6F 6C 6C 65 72 20 62 79   oller by
$28: 3A 20 4A 61 79 20 43 61   : Jay Ca
$30: 72 6C 73 6F 6E 20 6F 66   rlson of
$38: 20 53 55 4E 42 55 52 53    SUNBURS
$40: 54 20 43 6F 6D 6D 75 6E   T Commun
$48: 69 63 61 74 69 6F 6E 73   ications
$50: 20 49 6E 63 2E 20 A0 A0    Inc.
$58: A0 A0 A0 A0 A0 A0 A0 A0
$60: A0 A0 A0 A0 28 43 29 20       (C)
$68: 53 55 4E 42 55 52 53 54   SUNBURST
$70: 20 43 6F 6D 6D 75 6E 69    Communi
$78: 63 61 74 69 6F 6E 73 2E   cations.

                 --^--

So thanks, Jay Carlson of Sunburst
Communications Inc., for a wild ride.

---------------------------------------
A 4am crack                    No. 2863
------------------EOF------------------
